#include<cstdio>
#include<iostream>
#include<cstdlib> // stdtod()
#include<cassert>
#include<string>
#include<cstring>
#include<cerrno>  //errno == ERANGE
#include<cmath>   //HUGE_VAL
#include<cctype>  //isdigit()
#include"shep_json.h"
using namespace std;

class shep_context{
public:
    const char* json;

    shep_context(char* data = nullptr) : json(data) {}

    void expect(char ch){assert(*json == ch); json++;}
};


static void shep_parse_whitespace(shep_context& c){
    const char *p = c.json;
    while(*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r'){
        p++;
    }
    c.json = p;
}


/**
 * @brief 解析 null/true/false 三种 json 串
 * @param c 要解析的 json 内容（已封装）
 * @param v 解析到的目标节点 
 * @param target_str 预期的解析串
 * @param target_state 解析成功后目标节点的标识状态
 * @return 解析结果
 */
static int shep_parse_literal(shep_context& c, shep_value& v, const char* target_str, shep_type target_state){
    c.expect(target_str[0]);
    target_str++;
    int len = strlen(target_str);
    while(*target_str != '\0'){
        if(*c.json != *target_str)return SHEP_PARSE_INVALID_VALUE;
        c.json++;
        target_str++;
    }
    v.set_type(target_state);
    return SHEP_PARSE_OK;
}

static inline bool isdigit1to9(const char& ch){return (isdigit(ch) && ch != '0');}

static bool validate_number(const char*& s){//验证数字字符串合法性
    if(*s == '-')s++;
    if(!isdigit(*s))return false;//为了排除 "-" 或者 "" 的情况
    if(isdigit1to9(*s)){
        while(isdigit(*s))s++;
    }
    if(*s == '0')s++;
    if(*s == '.'){
        s++;
        if(!isdigit(*s))return false;
        while(isdigit(*s))s++;
    }
    if(*s == '\0')return true;
    if(*s == 'e' || *s == 'E'){
        s++;
        if(*s == '+' || *s == '-')s++;
        if(!isdigit(*s))return false;  
        while(isdigit(*s))s++;
        if(*s == '\0')return true;
    }
    //这里设置为 true 放过了以 0 开头的非法字符串比如 “0123”
    //因为这种字符应该解析为 SHEP_PARSE_ROOT_NOT_SINGULAR 类型而不是
    //SHEP_PARSE_INVALID_VALUE ！ 我不能理解，我觉得应该是后者，先暂且按作者的写，后面再说。
    return true;
}


/**
 * @brief 解析数字类型的 json
 * @param c 要解析的 json 字符串
 * @param v 解析后的 json 节点
 * @return 解析结果
 */
static int shep_parse_number(shep_context& c, shep_value& v){
    //char* end;
    /* \TODO validate number */
    const char* temp = c.json;
    if(!validate_number(temp))return SHEP_PARSE_INVALID_VALUE;//这里用另一个指针做数字合法性验证，不能用原指针，会动原指针的。
    errno = 0;
    double convert_res = strtod(c.json, nullptr);//将 str 转为 double 并返回转换结果。
    if(errno == ERANGE && (convert_res == HUGE_VAL || convert_res == -HUGE_VAL))return SHEP_PARSE_NUMBER_TOO_BIG;
    v.set_number(convert_res);
    // if(c.json == end){//不是一个合法值(不是 strtod()允许的合法值，这个判断条件对于我们的需求太过宽松。)
    //     return SHEP_PARSE_INVALID_VALUE;
    // }
    c.json = temp;
    v.set_type(SHEP_NUMBER);
    return SHEP_PARSE_OK;
}

static const char* shep_parse_hex4(const char* p, unsigned int& u){
    u = 0;
    p++;
    int i = 0;
    while(true){
        if(*p <= '9' && *p >= '0')u += (*p - '0');   
        else if(*p <= 'F' && *p >= 'A')u += (*p - 'A' + 0b1010);
        else if(*p <= 'f' && *p >= 'a')u += (*p - 'a' + 0b1010);
        else return nullptr;
        i++;
        if(i > 3)break;
        p++;
        u <<= 4;
    }
    return p;
}

static void shep_encode_utf8(unsigned int u, string &temp){
    if(u <= 0x007f)temp += char(u);
    else if(u <= 0x07ff){
        temp += char(0xc0 | (0x1f & (u >> 6)));
        temp += char(0x80 | (0x3f & u));
    }
    else if(u <= 0xffff){
        temp += char(0xe0 | (0x0f & (u >> 12)));
        temp += char(0x80 | (0x3f & (u >> 6)));
        temp += char(0x80 | (0x3f & u));
    }
    else if(u <= 0x10ffff){
        temp += char(0xf0 | (0x03 & (u >> 18)));
        temp += char(0x80 | (0x3f & (u >> 12)));
        temp += char(0x80 | (0x3f & (u >> 6)));
        temp += char(0x80 | (0x3f & u));
    }
}



static int shep_parse_string(shep_context& c, shep_value& v){
    assert(*c.json == '\"');
    string temp = "";
    const char* p = c.json;
    while(true){
        p++;
        switch(*p){
            case '\"':
                v.set_string(temp.c_str(), temp.length());
                c.json = p;
                c.json++;
                return SHEP_PARSE_OK;
            case '\0':
                return SHEP_PARSE_MISS_QUOTATION_MARK;
            case '\\':
                switch (*++p){
                    case '\"': temp += '\"'; break;
                    case '\\': temp += '\\'; break;
                    case '/': temp += '/'; break;
                    case 'b': temp += '\b'; break;
                    case 'f': temp += '\f'; break;
                    case 'n': temp += '\n'; break;
                    case 'r': temp += '\r'; break;
                    case 't': temp += '\t'; break;
                    case 'u': { 
                        unsigned int u;
                        if(!(p = shep_parse_hex4(p, u)))return SHEP_PARSE_INVALID_UNICODE_HEX;
                        if(u <= 0xdbff && u >= 0xd800){
                            if(*++p != '\\')return SHEP_PARSE_INVALID_UNICODE_SURROGATE;
                            if(*++p != 'u')return SHEP_PARSE_INVALID_UNICODE_SURROGATE;
                            unsigned int r;
                            if(!(p = shep_parse_hex4(p, r)))return SHEP_PARSE_INVALID_UNICODE_SURROGATE;
                            if(r < 0xdc00 || r > 0xdfff)return SHEP_PARSE_INVALID_UNICODE_SURROGATE;
                            u = 0x10000 + ((u - 0xd800) << 10) | (r - 0xdc00);
                        }
                        shep_encode_utf8(u, temp);
                        break;
                    }
                    default:
                        return SHEP_PARSE_INVALID_STRING_ESCAPE;
                    }
                break;
            default:
                if((unsigned char)*p < 0x20){//非法 字符
                    return SHEP_PARSE_INVALID_STRING_CHAR;
                }
                temp += *p;
        }
    }
}

static int shep_parse_value(shep_context& c, shep_value& v){
    switch(*c.json){
        case 'n':  return shep_parse_literal(c, v, "null", SHEP_NULL);
        case 't':  return shep_parse_literal(c, v, "true", SHEP_TRUE);
        case 'f':  return shep_parse_literal(c, v, "false", SHEP_FALSE);
        case '"':  return shep_parse_string(c, v);
        case '\0': return SHEP_PARSE_EXCEPT_VALUE;
        default:   return shep_parse_number(c, v); 
    }
}


/**
 * @brief 将 json 字符串解析成 json 节点结构
 * @param v 目标 json 节点
 * @param json 要解析的 json 字符串
 * @return 解析结果
 */
int shep_parse(shep_value& v, const char* json){
    shep_context c;
    c.json = json;
    v.set_type(SHEP_NULL);
    shep_parse_whitespace(c);
    int temp_val = shep_parse_value(c, v);
    if(temp_val != SHEP_PARSE_OK)return temp_val;
    shep_parse_whitespace(c);
    if(*c.json != '\0'){
        v.set_type(SHEP_NULL);//如果出问题要把 type 重置为 SHEP_NULL
        temp_val = SHEP_PARSE_ROOT_NOT_SINGULAR; 
    }
    return temp_val;
}